#include "Math/BaseMath.h"

namespace GCRE {
	namespace Math{

		using namespace BasicType;

		BasicType::SFFloat cos( BasicType::SFFloat rad )
		{
			__asm {
				fld rad // r0 = rad
				fcos // r0 = cosf( r0 )
			} // returns r0
		}

		BasicType::SFFloat sin( BasicType::SFFloat rad )
		{
			__asm {
				fld rad // r0 = rad
				fsin // r0 = sinf( r0 )
			} // returns r0
		}

		BasicType::SFFloat tan( BasicType::SFFloat rad )
		{
			// return sin( rad ) / cos( rad );
			__asm {
				fld rad // r0 = rad
				fsin // r0 = sinf( r0 )
				fld rad // r1 = r0, r0 = rad
				fcos // r0 = cosf( r0 )
				fdiv // r0 = r1 / r0
			} // returns r0
		}

		BasicType::SFFloat arccos( BasicType::SFFloat value )
		{
			// return half_pi + arctan( value / -sqr( 1.f - value * value ) );

			const SFFloat one = 1.0F;
			__asm {
				fld value // r0 = value
				fld value // r1 = r0, r0 = value
				fmul value // r0 = r0 * value
				fsubr one // r0 = r0 - 1.f
				fsqrt // r0 = sqrtf( r0 )
				fchs // r0 = - r0
				fdiv // r0 = r1 / r0
				fld1 // {{ r0 = atan( r0 )
				fpatan // }}
				fadd half_pi // r0 = r0 + pi / 2
			} // returns r0
		}

		BasicType::SFFloat arcsin( BasicType::SFFloat value )
		{
			// return arctan( value / sqr( 1.f - value * value ) );
			const SFFloat one = 1.0F;
			__asm {
				fld value // r0 = value
				fld value // r1 = r0, r0 = value
				fmul value // r0 = r0 * value
				fsubr one // r0 = r0 - 1.f
				fsqrt // r0 = sqrtf( r0 )
				fdiv // r0 = r1 / r0
				fld1 // {{ r0 = atan( r0 )
				fpatan // }}
			} // returns r0
		}

		BasicType::SFFloat arctan( BasicType::SFFloat value )
		{
			__asm {
				fld value // r0 = value
				fld1 // {{ r0 = atan( r0 )
				fpatan // }}
			} // returns r0
		}

		BasicType::SFFloat sqrt( BasicType::SFFloat value )
		{
			__asm {
				fld value // r0 = value
				fsqrt // r0 = sqrtf( r0 )
			} // returns r0
		}

		BasicType::SFFloat pow2( BasicType::SFFloat value )
		{
			__asm {
				fld value	//	r0 = value
				fmul value	//	r0 = r0 * value
			}	//	returns r0
		}

		BasicType::SFFloat abs( BasicType::SFFloat value )
		{
			__asm {
				fld value	//	r0 = value
				fabs	// r0 = abs( r0 )
			}	//	returns r0
		}

		BasicType::SFFloat round( BasicType::SFFloat value )
		{
			SFFloat value_floor = ::floor( value );
			return ( value - value_floor >= 0.5F ? value_floor + 1 : value_floor ) ;
		}

	}
}